import ustruct
import ubinascii
import utime as time


class number_toolkit:
    def crc16_xaiot(strArray: str):
        if strArray is None:
            return 0
        crc = 0xFFFF
        # data : bytearray
        byte_array_data = ubinascii.unhexlify(strArray)

        for i in range(0, len(byte_array_data)):
            crc ^= byte_array_data[i] << 8
            for j in range(0, 8):
                if (crc & 0x8000) > 0:
                    crc = (crc << 1) ^ 0x1021
                else:
                    crc = crc << 1
        resultCrc = str(hex(crc & 0xFFFF))
        resultCrc = resultCrc[2 : len(resultCrc)]
        while len(resultCrc) < 4:
            resultCrc = "0" + resultCrc
        return resultCrc

    def bytearray_to_bin(bta):
        resultValue = 0
        for b in bta:
            resultValue += b * 256
        return resultValue

    def str_to_binary(str):  # 将字符串转成二进制

        i = 0
        hexBytArr = bytearray()
        while i < len(str):

            bodyArr = str[i : i + 2]
            intEle = int("0x" + bodyArr, 16)
            bt = bytearray([intEle])
            hexBytArr += bt

            i += 2

        return hexBytArr

    def hex2float(s: str) -> float:
        return ustruct.unpack("!f", bytes.fromhex(s))[0]

    def float2hex(f: float) -> str:
        fullHexStr = hex(ustruct.unpack(">I", ustruct.pack(">f", f))[0])
        fullHexStr = fullHexStr[2 : len(fullHexStr)]
        while len(fullHexStr) < 6:
            fullHexStr = "0" + fullHexStr
        return fullHexStr

    def funId2Hex(fID: int) -> str:
        hexStr = hex(fID)
        return hexStr[2 : len(hexStr)]

    def int2hex(oriInt: int) -> str:
        hexStr = ""
        shrinkInt = oriInt
        leftInt = 0
        while shrinkInt > 15:
            leftInt = shrinkInt % 16
            full_16 = int(shrinkInt - leftInt) / 16
            hexStr = str(full_16) + hexStr
            shrinkInt = shrinkInt - full_16 * 16 + leftInt
        hexStr = "{0:02x}".format(shrinkInt) + hexStr

        return hexStr

    def get_messageID() -> str:

        nowTime = time.time()
        messageID = str(hex(nowTime))
        # print('time', nowTime, messageID,messageID[2:len(messageID)])

        messageID = messageID[2 : len(messageID)]
        if len(messageID) > 8:
            messageID = messageID[0:8]
        while len(messageID) < 8:
            messageID += "f"
        return messageID

    def composeTlV(self, funcID, dataType, devValue) -> bytearray:
        print('composeTlV funcID: ', funcID, ' dataType: ', dataType, ' devValue: ', devValue)

        messageID = self.get_messageID()
        modbusValue = ""
        if dataType == "FLOAT":
            modbusValue = self.float2hex(devValue)
        elif dataType == "int":
            modbusValue = self.int2hex(devValue)
        elif dataType == "BOOLEAN":
            modbusValue = self.int2hex(devValue)

        bodyStr = "81" + messageID + "03" + self.funId2Hex(funcID) + modbusValue
        print('composeTlV bodyStr: ', bodyStr)

        crc = self.crc16_xaiot(bodyStr)
        bodyStr += crc
        # print(
        #     "messageID 81: ",
        #     messageID,
        #     " funcID 03: ",
        #     funcID,
        #     " modbusValue: ",
        #     modbusValue,
        #     "crc:",
        #     crc,
        # )

        i = 0
        hexBytArr = bytearray()
        while i < len(bodyStr):

            bodyArr = bodyStr[i : i + 2]
            intEle = int("0x" + bodyArr, 16)
            bt = bytearray([intEle])
            hexBytArr += bt

            i += 2

        return hexBytArr

    def composeTlVs(self, tlv_list) -> bytearray:
        # print('funcID: ', funcID, ' dataType: ', dataType, ' devValue: ', devValue)

        messageID = self.get_messageID()
        tlv = "81" + messageID
        for tlv_item in tlv_list:
            modbusValue = ""
            if tlv_item["dataType"] == "FLOAT":
                modbusValue = self.float2hex(tlv_item["devValue"])
            elif tlv_item["dataType"] == "int":
                modbusValue = self.int2hex(tlv_item["devValue"])
            elif tlv_item["dataType"] == "BOOLEAN":
                modbusValue = self.int2hex(tlv_item["devValue"])

            tlv += "03" + self.funId2Hex(tlv_item["funcID"]) + modbusValue

        crc = self.crc16_xaiot(tlv)
        tlv += crc
        # print(
        #     "messageID 81: ",
        #     messageID,
        #     " tlv: ",
        #     tlv,
        #     "crc:",
        #     crc,
        # )

        i = 0
        hexBytArr = bytearray()
        while i < len(tlv):

            bodyArr = tlv[i : i + 2]
            intEle = int("0x" + bodyArr, 16)
            bt = bytearray([intEle])
            hexBytArr += bt

            i += 2

        return hexBytArr

    def compose_down_reply(self, msg_id) -> bytearray:
        # print('funcID: ', funcID, ' dataType: ', dataType, ' devValue: ', devValue)
        msg = "81" + msg_id + "8200"
        crc = self.crc16_xaiot(msg)
        msg += crc
        # print(
        #     " msg: ",
        #     msg,
        #     "crc:",
        #     crc,
        # )

        i = 0
        hexBytArr = bytearray()
        while i < len(msg):

            bodyArr = msg[i : i + 2]
            intEle = int("0x" + bodyArr, 16)
            bt = bytearray([intEle])
            hexBytArr += bt

            i += 2

        return hexBytArr
